package com.ls.rabbitmqService;

import com.alibaba.fastjson.JSONObject;
import com.rabbitmq.client.Channel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * rabbitmq 发送消息
 */
public class RabbitmqSendMessage {

    static Logger logger = LoggerFactory.getLogger(RabbitmqConnectionPool.class);
    /**
     * 消息队列名称字符串，格式x.x.x.x 中间代表地区 后面是第几个队列
     * 队列默认都是持久化的，但是消息暂时不需要持久化，路由器已默认的direct直连的方式
     * 例如:
     * rabbitmq.hb.mj.queue
     * rabbitmq.hb.poker.queue
     * rabbitmq.hb.hall.queue
     */
    public static String queueName="rabbitmq.nx.test.queue";
    //地区
    public static String area="nx";

    //一次最多推送的个数
    static final int maxPushNum=1000;

    public static String username="pushUser";
    public static String password="1qa2ws";
    public static String virtualHost="/";
    public static String host="47.93.157.178";
    public static int port=5672;
    static{
        RabbitmqConnectionPool.initConnectionFactory(username,password,virtualHost,host,port);
    }

    public  enum PlatformType{
        ALL("all"),ANDROID("android"),IOS("ios");
        private String name;
        PlatformType(String name) {
            this.name = name;
        }
        public String getName() {
            return name;
        }
    }

    public  enum SendType{
        ONE("one"),BATCH("batch"),ALL("all");
        private String name;
        SendType(String name) {
            this.name = name;
        }
        public String getName() {
            return name;
        }
    }

    public  enum PushType{
        NOTIFICATION("notification"),MESSAGE("message");
        private String name;
        PushType(String name) {
            this.name = name;
        }
        public String getName() {
            return name;
        }
    }

    /**
     * 发送消息的格式 给指定某个用户推送消息
     * 例如给别名为hb_1的用户推送一个通知  不带参数
     * 如果需要带参数可以在data对象添加属性即可
     *
     * @param uid
     * @param message
     */
    /**
     * 发送消息的格式 给指定某个用户推送消息
     * rabbitmq 收到的格式{'uid':1,'area':'hb','pushType':'notification','sendType':'one','platformType':'all','data':{'message':'msg','key':'value'}}
     * key:value 是map传递过来的值  platformType平台类型android,ios,all
     * sendType 的值为one单条  batch批量
     * pushType 推送类型，暂时支持通知
     * @param message 推送的消息
     * @param platformType 用户的平台类型，枚举类
     * @param parameters 袖带参数 默认是不需要传递的，暂时只有弹框通知，
     *                   不需要参数，如果带参数可以传递一个Map对象即可,传递多个也只会用一个
     *                   袖带参数为key:value的形式
     */
    public static void broadcastMessage(String queueName,String area,String message,PlatformType platformType,Map<String,Object>...parameters){
        if(platformType==null){
            platformType=PlatformType.ALL;
        }
        RabbitmqChannelPool.RabbitmqChannel rabbitmqChannel = RabbitmqChannelPool.getChannel();
        if(rabbitmqChannel==null || rabbitmqChannel.getChannel()==null){
            logger.error("RabbitmqSendMessage sendMessage channel is null");
            logger.warn("消息丢失 broad:{},body:{}",message);
        }else{
            Channel channel = rabbitmqChannel.getChannel();
            /**
             logger.info("[*] producer waiting for message  threadName:{},tcpId:{},channelNum:{},channelId:{},currentConnectionNum:{},maxConnectionNum:{},maxTcpChannelNum:{}",
             Thread.currentThread().getName(),rabbitmqChannel.getConnection().getId(),
             rabbitmqChannel.getConnection().getNewChannelNum(),channel.hashCode()
             ,RabbitmqConnectionPool.currentConnectionNum,RabbitmqConnectionPool.maxConnectionNum,RabbitmqChannelPool.maxTcpChannelNum);
             **/
            try {
                channel.queueDeclare(queueName,true,false,false,null);
                JSONObject jsonObject=new JSONObject();
                jsonObject.put("platformType",platformType==null?PlatformType.ALL.getName():platformType.getName());
                jsonObject.put("sendType",SendType.ALL.getName());
                jsonObject.put("pushType",PushType.NOTIFICATION.getName());
                jsonObject.put("area",area);
                Map<String,Object> result=new HashMap<String,Object>();
                result.put("message",message);
                if(parameters!=null && parameters.length>0){
                    result.putAll(parameters[0]);
                }
                jsonObject.put("data",result);
                channel.basicPublish("",queueName,null,jsonObject.toJSONString().getBytes());
            } catch (IOException e) {
                e.printStackTrace();
            }finally{
                rabbitmqChannel.close();
            }
        }
    }

    /**
     * 发送消息的格式 给指定某个用户推送消息
     * 例如给别名为hb_1的用户推送一个通知  不带参数
     * 如果需要带参数可以在data对象添加属性即可
     *
     * @param uid
     * @param message
     */
    /**
     * 发送消息的格式 给指定某个用户推送消息
     * rabbitmq 收到的格式{'uid':1,'area':'hb','pushType':'notification','sendType':'one','platformType':'all','data':{'message':'msg','key':'value'}}
     * key:value 是map传递过来的值  platformType平台类型android,ios,all
     * sendType 的值为one单条  batch批量
     * pushType 推送类型，暂时支持通知
     * @param queueName 队列名称
     * @param pushType 推送类型
     * @param uid 用户id
     * @param message 推送的消息
     * @param platformType 用户的平台类型，枚举类
     * @param parameters 袖带参数 默认是不需要传递的，暂时只有弹框通知，
     *                   不需要参数，如果带参数可以传递一个Map对象即可,传递多个也只会用一个
     *                   袖带参数为key:value的形式
     */
    public static void pushMsg(String queueName,String area,PushType pushType,int uid, String message,PlatformType platformType,Map<String,Object>...parameters){
        if(platformType==null){
            platformType=PlatformType.ALL;
        }
        RabbitmqChannelPool.RabbitmqChannel rabbitmqChannel = RabbitmqChannelPool.getChannel();
        if(rabbitmqChannel==null || rabbitmqChannel.getChannel()==null){
            logger.error("RabbitmqSendMessage sendMessage channel is null");
            logger.warn("消息丢失 uid:{},body:{}",uid,message);
        }else{
            Channel channel = rabbitmqChannel.getChannel();
            /**
             logger.info("[*] producer waiting for message  threadName:{},tcpId:{},channelNum:{},channelId:{},currentConnectionNum:{},maxConnectionNum:{},maxTcpChannelNum:{}",
             Thread.currentThread().getName(),rabbitmqChannel.getConnection().getId(),
             rabbitmqChannel.getConnection().getNewChannelNum(),channel.hashCode()
             ,RabbitmqConnectionPool.currentConnectionNum,RabbitmqConnectionPool.maxConnectionNum,RabbitmqChannelPool.maxTcpChannelNum);
             **/
            try {
                channel.queueDeclare(queueName,true,false,false,null);
                JSONObject jsonObject=new JSONObject();
                jsonObject.put("uid",uid);
                jsonObject.put("platformType",platformType==null?PlatformType.ALL.getName():platformType.getName());
                jsonObject.put("sendType",SendType.ONE.getName());
                jsonObject.put("pushType",pushType.getName());
                jsonObject.put("area",area);
                Map<String,Object> result=new HashMap<String,Object>();
                result.put("message",message);
                if(parameters!=null && parameters.length>0){
                    result.putAll(parameters[0]);
                }
                jsonObject.put("data",result);
                channel.basicPublish("",queueName,null,jsonObject.toJSONString().getBytes());
            } catch (IOException e) {
                e.printStackTrace();
            }finally{
                rabbitmqChannel.close();
            }
        }
    }


    public static void sendMessage(int uid, String message,PlatformType platformType,Map<String,Object>...parameters){
        pushMsg(queueName,area,PushType.NOTIFICATION,uid,message,platformType,parameters);
    }

    public static void sendMessage(List<Integer> uids, String message,PlatformType platformType,Map<String,Object>...parameters){
        sendMessage(queueName,area,uids,message,platformType,parameters);
    }
    /**
     * 给多个用户发送同样的消息，最好是每次发送1000个
     * 因为激光推送给一批用户，平台是一样的，所以这个平台类型最好为all
     */
    public static void sendMessage(String queueName,String area,List<Integer> uids, String message,PlatformType platformType,Map<String,Object>...parameters){
        if(uids==null || uids.size()<0){
            logger.warn("uids==null || uids.size()<0");
            return;
        }
        if(platformType==null){
            platformType=PlatformType.ALL;
        }
        RabbitmqChannelPool.RabbitmqChannel rabbitmqChannel = RabbitmqChannelPool.getChannel();
        if(rabbitmqChannel==null || rabbitmqChannel.getChannel()==null){
            logger.error("RabbitmqSendMessage sendMessage channel is null");
            logger.warn("消息丢失 uid size:{},body:{}",uids.size(),message);
        }else{
            Channel channel = rabbitmqChannel.getChannel();
            /**
             logger.info("[*] producer waiting for message  threadName:{},tcpId:{},channelNum:{},channelId:{},currentConnectionNum:{},maxConnectionNum:{},maxTcpChannelNum:{}",
             Thread.currentThread().getName(),rabbitmqChannel.getConnection().getId(),
             rabbitmqChannel.getConnection().getNewChannelNum(),channel.hashCode()
             ,RabbitmqConnectionPool.currentConnectionNum,RabbitmqConnectionPool.maxConnectionNum,RabbitmqChannelPool.maxTcpChannelNum);
             **/
            try {
                channel.queueDeclare(queueName,true,false,false,null);
                JSONObject jsonObject=new JSONObject();
                jsonObject.put("platformType",platformType==null?PlatformType.ALL.getName():platformType.getName());
                jsonObject.put("sendType",SendType.BATCH.getName());
                jsonObject.put("pushType",PushType.NOTIFICATION.getName());
                jsonObject.put("area",area);
                Map<String,Object> result=new HashMap<String,Object>();
                result.put("message",message);
                if(parameters!=null && parameters.length>0){
                    result.putAll(parameters[0]);
                }
                jsonObject.put("data",result);
                int num=uids.size()/maxPushNum;
                if(uids.size()%maxPushNum>0){
                    num++;
                }
                int start=0;
                int end=0;
                for(int i=0;i<num;i++){
                    start=i*maxPushNum;
                    end=(i+1)*maxPushNum;
                    if(end>uids.size()){
                        end=uids.size();
                    }
                    jsonObject.put("uids",uids.subList(start,end));
                    channel.basicPublish("",queueName,null,jsonObject.toJSONString().getBytes());
                }
            } catch (IOException e) {
                e.printStackTrace();
            }finally{
                rabbitmqChannel.close();
            }
        }
    }


    public static void sendMessage(String message){
        sendMessage(queueName,message);
    }
    //发送单个消息
    public static void sendMessage(String queueName,String message){
        RabbitmqChannelPool.RabbitmqChannel rabbitmqChannel = RabbitmqChannelPool.getChannel();
        if(rabbitmqChannel==null || rabbitmqChannel.getChannel()==null){
            logger.error("RabbitmqSendMessage sendMessage channel is null");
            logger.warn("消息丢失 body:"+message);
        }else{
            Channel channel = rabbitmqChannel.getChannel();
            /**
            logger.info("[*] producer waiting for message  threadName:{},tcpId:{},channelNum:{},channelId:{},currentConnectionNum:{},maxConnectionNum:{},maxTcpChannelNum:{}",
                    Thread.currentThread().getName(),rabbitmqChannel.getConnection().getId(),
                    rabbitmqChannel.getConnection().getNewChannelNum(),channel.hashCode()
                    ,RabbitmqConnectionPool.currentConnectionNum,RabbitmqConnectionPool.maxConnectionNum,RabbitmqChannelPool.maxTcpChannelNum);
            **/
            try {
                channel.queueDeclare(queueName,true,false,false,null);
                channel.basicPublish("",queueName,null,message.getBytes());
            } catch (IOException e) {
                e.printStackTrace();
            }finally{
                rabbitmqChannel.close();
            }
        }
    }

    public static void sendMessage(List<String> messages){
        sendMessage(queueName,messages);
    }
    //发送多个消息
    public static void sendMessage(String queueName,List<String> messages){
        RabbitmqChannelPool.RabbitmqChannel rabbitmqChannel = RabbitmqChannelPool.getChannel();
        if(rabbitmqChannel==null || rabbitmqChannel.getChannel()==null){
            logger.error("RabbitmqSendMessage sendMessage channel is null");
            logger.warn("消息丢失 size:"+messages.size());
        }else{
            Channel channel = rabbitmqChannel.getChannel();
            try {
                channel.queueDeclare(queueName,true,false,false,null);
                for(String message:messages)
                    channel.basicPublish("",queueName,null,message.getBytes());
            } catch (IOException e) {
                e.printStackTrace();
            }finally{
                rabbitmqChannel.close();
            }
        }
    }

}
